package tests;

import java.util.List;

import jeconbond.automata.INode;
import jeconbond.automata.IOutcome;
import jeconbond.automata.Node;
import jeconbond.automata.Outcome;
import jeconbond.automata.behaviour.IAutomataWalkListener;
import jeconbond.automata.behaviour.IWalkStrategy;
import jeconbond.economic.agent.AutomataAgent;
import jeconbond.economic.resources.ResourceType;
import jeconbond.economic.resources.IResourceType;
import jeconbond.economic.resources.ResourceBasket;
import junit.framework.Assert;
import junit.framework.TestCase;

public class TestAutomataSupport extends TestCase {
	public void testWalking() {
		INode rootNode = new Node("root");
		INode node_0 = new Node("n0");
		rootNode.getOutcomes().add(new Outcome(node_0));
		INode node_1 = new Node("n1");
		rootNode.getOutcomes().add(new Outcome(node_1));
		INode node_0_0 = new Node("n00");
		node_0.getOutcomes().add(new Outcome(node_0_0));
		
		String name00 = rootNode.getOutcomes().get(0).getDestination()
			.getOutcomes().get(0).getDestination().getName();
		Assert.assertEquals("n00", name00);
	}
	
	public void testResourcesCustoming() {
		IResourceType wood = new ResourceType("Wood");
		IResourceType stone = new ResourceType("Stone");
		INode node1 = new Node("n1");
		INode node2 = new Node("n2");
		node1.getOutcomes().add(
				new Outcome(
						node2,
						new ResourceBasket(wood, 1.0),
						new ResourceBasket(stone, 2.0)
						)
				);
		Assert.assertEquals("Wood", node1.getOutcomes().get(0).getRequirements()[0].type.getName());
		Assert.assertEquals("Stone", node1.getOutcomes().get(0).getRequirements()[1].type.getName());
		Assert.assertEquals(2.0, node1.getOutcomes().get(0).getRequirements()[1].value);
	}
	
	public void testIOutcome() {
		IResourceType wood = new ResourceType("Wood");
		IOutcome out = new Outcome(new Node("1"), new ResourceBasket(wood, 1.0));
		out.setProducedResources(new ResourceBasket(wood, 2.0), new ResourceBasket(wood, 0.2));
		double producedWood = 0.0;
		for (ResourceBasket rb : out.getProducedResources()) {
			producedWood += rb.value;
			Assert.assertEquals("Wood", rb.type.getName());
		}
		Assert.assertEquals(2.2, producedWood);
	}
	
	private static class OddValker implements IWalkStrategy {
		private IOutcome[] outs;
		private int pos = 0;
		private int counter = 0;
		public OddValker(IOutcome ... outs) {
			this.outs = outs;
		}
		public IOutcome doWalk(INode state) {
			counter++;
			if (counter % 2 == 0) {
				return null;
			}
			pos = (pos + 1) % outs.length;
			return outs[pos];
		}
	}
	
	public void testAutomataAgentEvents() {
		INode root = new Node("root");
		INode n1 = new Node("n1");
		IOutcome out1 = new Outcome(n1);
		root.getOutcomes().add(out1);
		IOutcome out2 = new Outcome(root);
		n1.getOutcomes().add(out2);
		
		final StringBuilder sb = new StringBuilder();
		
		AutomataAgent agent = new AutomataAgent(root);
		agent.setMerchant(new tests.fakes.StoreCallsMerchant());
		agent.setWalkStrategy(new OddValker(out1, out2));
		agent.setWalkingListener(
				new IAutomataWalkListener() {
					private int counter = 0;
					public void onWalkingPerformed(INode from, INode to) {
						sb.append(counter++);
					}
					public void sameState(INode state) {
						counter++;
					}
					public List<Double> getReport() { return null; }
				}
		);
		agent.processPreProduceStage();
		agent.processProduceStage();
		agent.processPostProduceStage();
		
		agent.processPreProduceStage();
		agent.processProduceStage();
		agent.processPostProduceStage();
		
		agent.processPreProduceStage();
		agent.processProduceStage();
		agent.processPostProduceStage();
		
		Assert.assertEquals("02", sb.toString());
	}
}
